package main

import (
	"fmt"
	"strconv"
	"unicode"
)

var consupdate chan int                   // 用于更新状态的通知通道
var consel [30]int                        // 选择器状态数组
var conscard [8][10]byte                  // 卡片数据存储
var signcard [8][2]byte                   // 卡片符号存储
var consj [10]byte                        // J寄存器数据
var signj [2]byte                         // J寄存器符号
var consk [10]byte                        // K寄存器数据
var signk [2]byte                         // K寄存器符号
var consout chan pulse                    // 输出脉冲通道
var conspin [30]chan pulse                // 输入脉冲通道数组
var consinff1, consinff2 [30]bool        // 状态标志数组
var conspout [30]chan pulse              // 输出脉冲通道数组

// 返回 consinff2 数组的状态字符串表示
func consstat() string {
	s := "" // 初始化空字符串用于存储状态
	for _, f := range consinff2 { // 遍历 consinff2 数组中的每个布尔值
		s += b2is(f) // 将布尔值转换为字符串并追加到 s 中
	}
	return s // 返回状态字符串
}

// 重置所有相关变量和通道到初始状态，并通知更新
func consreset() {
	// 重置选择器、输入脉冲通道、状态标志和输出脉冲通道
	for i := 0; i < 30; i++ {
		consel[i] = 0                     // 选择器状态设为 0
		conspin[i] = nil                  // 输入脉冲通道设为空
		consinff1[i] = false              // 状态标志1设为 false
		consinff2[i] = false              // 状态标志2设为 false
		conspout[i] = nil                 // 输出脉冲通道设为空
	}

	// 重置卡片数据和符号
	for i := 0; i < 8; i++ {
		for j := 0; j < 10; j++ {
			conscard[i][j] = 0            // 卡片数据设为 0
		}
		signcard[i][0] = 0                // 卡片符号1设为 0
		signcard[i][1] = 0                // 卡片符号2设为 0
	}

	// 重置 J 和 K 寄存器的数据和符号
	for i := 0; i < 10; i++ {
		consj[i] = 0                      // J寄存器数据设为 0
		consk[i] = 0                      // K寄存器数据设为 0
	}
	signj[0] = 0                         // J寄存器符号1设为 0
	signj[1] = 0                         // J寄存器符号2设为 0
	signk[0] = 0                         // K寄存器符号1设为 0
	signk[1] = 0                         // K寄存器符号2设为 0

	consout = nil                        // 输出脉冲通道设为空
	consupdate <- 1                      // 发送更新通知
}

// 根据插槽名称和通道连接相应的输入或输出通道
func consplug(jack string, ch chan pulse) {
	var prog int    // 程序编号
	var ilk rune    // 插槽类型 ('i' 或 'o')

	if jack == "o" { // 如果插槽是输出
		consout = ch // 连接输出通道
	} else {
		fmt.Sscanf(jack, "%d%c", &prog, &ilk) // 解析插槽名称
		if ilk == 'i' {                       // 如果插槽是输入
			conspin[prog-1] = ch               // 连接输入通道
		} else {                              // 否则为输出
			conspout[prog-1] = ch              // 连接输出通道
		}
	}
	consupdate <- 1 // 发送更新通知
}

// 将字符串 'p' 或 'P' 转换为 0，其他转换为 1
func pm2int(ch string) byte {
	if ch == "p" || ch == "P" { // 如果字符串是 'p' 或 'P'
		return 0                    // 返回 0
	} else {
		return 1                    // 否则返回 1
	}
}

// 处理控制命令
func consctl(ch chan [2]string) {
	var n int

	selector := map[string]int{"l": 0, "r": 1, "lr": 2} // 定义选择器映射

	for {
		ctl := <-ch // 从通道接收控制命令
		switch ctl[0][0] {
		case 's': // 处理 's' 命令
			prog, _ := strconv.Atoi(ctl[0][1:]) // 解析程序编号
			switch ctl[1][0] {
			case 'a', 'A', 'c', 'C', 'e', 'E', 'g', 'G', 'j', 'J':
				n = 0
			case 'b', 'B', 'd', 'D', 'f', 'F', 'h', 'H', 'k', 'K':
				n = 3
			}
			consel[prog-1] = n + selector[ctl[1][1:]] // 设置选择器状态
		case 'j', 'J': // 处理 'j' 或 'J' 命令
			if ctl[0][1] == 'l' {
				signj[0] = pm2int(ctl[1]) // 设置 J 寄存器左符号
			} else if ctl[0][1] == 'r' {
				signj[1] = pm2int(ctl[1]) // 设置 J 寄存器右符号
			} else {
				digit, _ := strconv.Atoi(ctl[0][1:])
				n, _ := strconv.Atoi(ctl[1])
				consj[digit-1] = byte(n)   // 设置 J 寄存器数据
			}
		case 'k', 'K': // 处理 'k' 或 'K' 命令
			if ctl[0][1] == 'l' {
				signk[0] = pm2int(ctl[1]) // 设置 K 寄存器左符号
			} else if ctl[0][1] == 'r' {
				signk[1] = pm2int(ctl[1]) // 设置 K 寄存器右符号
			} else {
				digit, _ := strconv.Atoi(ctl[0][1:])
				n, _ := strconv.Atoi(ctl[1])
				consk[digit-1] = byte(n)   // 设置 K 寄存器数据
			}
		default:
			fmt.Println("Invalid constant switch: ", ctl[0]) // 打印无效命令错误信息
		}
	}
}

// 处理输入字符串 c，将其分割成每10个字符的字段，并调用 procfield 处理每个字段
func proccard(c string) {
	l := len(c) // 获取输入字符串的长度
	if l > 80 { // 如果长度超过80，截取前80个字符
		l = 80
	}
	for i := 0; i < l/10; i++ { // 遍历每个10字符的字段
		procfield(i, c[10*i:10*i+10]) // 调用 procfield 处理每个字段
	}
}

// 处理单个10字符的字段 f，根据选择器状态决定如何处理该字段
func procfield(i int, f string) {
	if len(f) < 10 || f == "          " { // 如果字段长度不足10或全为空格，直接返回
		return
	}
	bank := i / 2 // 计算字段对应的 bank 编号
	tendig := true // 假设需要处理整个字段

	// 检查选择器状态，决定是否需要将字段拆分为两个部分处理
	for j := bank * 6; j < bank*6+6; j++ {
		switch consel[j] {
		case 0, 1:
			if i%2 == 0 && conspin[j] != nil { // 如果是偶数字段且输入通道不为空
				tendig = false // 不需要处理整个字段
			}
		case 3, 4:
			if i%2 == 1 && conspin[j] != nil { // 如果是奇数字段且输入通道不为空
				tendig = false // 不需要处理整个字段
			}
		}
	}

	if tendig { // 如果需要处理整个字段
		donum(i, 0, f) // 直接处理整个字段
	} else { // 否则拆分为两部分处理
		donum(i, 0, f[:5]) // 处理前5个字符
		donum(i, 5, f[5:]) // 处理后5个字符
	}
}

// 根据偏移量 off 处理数字字符串 f，并存储到 conscard 和 signcard 中
func donum(i, off int, f string) {
	var nz int // 用于记录非零字符的位置

	neg := byte(0) // 初始化负号标志
	for _, c := range f { // 遍历字符串中的每个字符
		if c == '-' || c == ']' || c == '}' || (c >= 'J' && c <= 'R') { // 检查是否有负号或特殊字符
			neg = 1 // 设置负号标志
		}
	}
	if off == 0 { // 如果偏移量为0，设置符号位
		signcard[i][0] = neg
	} else {
		signcard[i][1] = neg
	}

	if neg == 0 { // 如果没有负号
		for j, c := range f { // 遍历字符串中的每个字符
			if unicode.IsDigit(c) { // 如果是数字
				conscard[i][9-(j+off)] = charval(c) // 将字符转换为数值并存储
			} else {
				conscard[i][9-(j+off)] = 0 // 否则存储为0
			}
		}
		return
	}

	// 如果有负号，处理负数
	l := len(f)
	for nz = l - 1; nz >= 0 && f[nz] == '0'; nz-- { // 找到第一个非零字符的位置
		conscard[i][9-(nz+off)] = '0' // 将所有尾随的0存储
	}
	for ; nz >= 0; nz-- { // 处理剩余的字符
		conscard[i][9-(nz+off)] = 9 - charval(rune(f[nz])) // 将字符转换为反向数值并存储
	}
}

// 将字符转换为其对应的数值
func charval(c rune) byte {
	if c == '-' || c == ']' || c == '}' { // 如果是负号或特殊字符
		return 0 // 返回0
	}
	if c >= 'J' && c <= 'R' { // 如果是大写字母 J 到 R
		return byte(c - 'J' + 1) // 转换为对应的数值（1到9）
	}
	return byte(c - '0') // 否则转换为对应的数字值（0到9）
}

// 根据选择器编号 sel 获取对应的符号、数值和位置信息
func getval(sel int) (sgn byte, val []byte, pos1pp int) {
	if sel >= 24 { // 如果选择器编号大于等于24，处理 J 和 K 寄存器
		pos1pp = -1 // 默认位置信息设为 -1
		switch consel[sel] {
		case 0:
			sgn = signj[0] // 设置符号为 J 寄存器左符号
			val = make([]byte, 10) // 初始化一个长度为10的字节数组
			copy(val[5:], consj[5:]) // 将 J 寄存器的后5个字符复制到 val 的后5个位置
			return
		case 1:
			sgn = signj[1] // 设置符号为 J 寄存器右符号
			val = make([]byte, 10)
			if sgn != 0 { // 如果有负号
				for i := 5; i < 10; i++ {
					val[i] = 9 // 后5个字符设为9
				}
			}
			copy(val[:5], consj[:5]) // 将 J 寄存器的前5个字符复制到 val 的前5个位置
			return
		case 2:
			return signj[0], consj[:], -1 // 返回 J 寄存器左符号和所有数据
		case 3:
			sgn = signk[0] // 设置符号为 K 寄存器左符号
			val = make([]byte, 10)
			copy(val[5:], consk[5:])
			return
		case 4:
			sgn = signk[1] // 设置符号为 K 寄存器右符号
			val = make([]byte, 10)
			if sgn != 0 {
				for i := 5; i < 10; i++ {
					val[i] = 9
				}
			}
			copy(val[:5], consk[:5])
			return
		case 5:
			return signk[0], consk[:], -1 // 返回 K 寄存器左符号和所有数据
		}
	} else { // 处理卡片数据
		bank := sel / 6 // 计算 bank 编号
		switch consel[sel] {
		case 0:
			sgn = signcard[2*bank][1] // 设置符号为卡片 bank 左符号
			val = make([]byte, 10)
			if sgn != 0 {
				for i := 0; i < 5; i++ {
					val[i] = 9 // 前5个字符设为9
				}
			}
			copy(val[5:], conscard[2*bank][5:]) // 将卡片 bank 的后5个字符复制到 val 的后5个位置
			pos1pp = 0
			return
		case 1:
			sgn = signcard[2*bank][0] // 设置符号为卡片 bank 右符号
			val = make([]byte, 10)
			copy(val[:5], conscard[2*bank][:5]) // 将卡片 bank 的前5个字符复制到 val 的前5个位置
			pos1pp = 5
			return
		case 2:
			return signcard[2*bank][0], conscard[2*bank][:], 0 // 返回卡片 bank 右符号和所有数据
		case 3:
			sgn = signcard[2*bank+1][1] // 设置符号为下一个 bank 左符号
			val = make([]byte, 10)
			if sgn != 0 {
				for i := 0; i < 5; i++ {
					val[i] = 9
				}
			}
			copy(val[5:], conscard[2*bank+1][5:])
			pos1pp = 0
			return
		case 4:
			sgn = signcard[2*bank+1][0] // 设置符号为下一个 bank 右符号
			val = make([]byte, 10)
			copy(val[:5], conscard[2*bank+1][:5])
			pos1pp = 5
			return
		case 5:
			return signcard[2*bank+1][0], conscard[2*bank+1][:], 0 // 返回下一个 bank 右符号和所有数据
		}
	}
	return
}

//这是一个预定义的数组，用于将字符转换为相应的数值。每个元素代表不同的组合值
var digitcons = []int{0, Onep, Twop, (Onep | Twop), Fourp, (Onep | Fourp),
	(Twop | Fourp), (Onep | Twop | Fourp), (Twop | Twopp | Fourp),
	(Onep | Twop | Twopp | Fourp)}

// 处理脉冲信号并根据当前状态更新相关变量
func consunit(cyctrunk chan pulse) {
	var val []byte
	var sign byte
	var pos1pp int
	var whichrp bool

	consupdate = make(chan int) // 创建更新通知通道
	go consunit2() // 启动辅助函数

	resp := make(chan int) // 创建响应通道

	for {
		p := <-cyctrunk // 接收脉冲信号
		sending := -1 // 初始化发送标志

		// 查找需要发送的字段
		for i := 0; i < 30; i++ {
			if consinff2[i] { // 如果该字段需要发送
				sending = i
				sign, val, pos1pp = getval(i) // 获取该字段的符号、值和位置信息
				break
			}
		}

		cyc := p.val // 获取脉冲信号的值

		// 处理 Ccg 和 Rp 信号
		if cyc&Ccg != 0 {
			whichrp = false
		} else if cyc&Rp != 0 {
			if whichrp {
				for i := 0; i < 30; i++ {
					if consinff1[i] {
						consinff1[i] = false
						consinff2[i] = true
					}
				}
				whichrp = false
			} else {
				whichrp = true
			}
		}

		// 发送处理
		if sending > -1 {
			if cyc&Cpp != 0 {
				handshake(1, conspout[sending], resp) // 发送握手信号
				consinff2[sending] = false
				sending = -1
			} else if cyc&Ninep != 0 {
				n := 0
				for i := uint(0); i < uint(10); i++ {
					if cyc&digitcons[val[i]] != 0 {
						n |= 1 << i // 根据 digitcons 表计算 n
					}
				}
				if sign == 1 {
					n |= 1 << 10 // 如果有负号，设置第10位
				}
				if n != 0 {
					handshake(n, consout, resp) // 发送握手信号
				}
			} else if cyc&Onepp != 0 && pos1pp >= 0 && sign == 1 {
				handshake(1<<uint(pos1pp), consout, resp) // 发送特定位置的握手信号
			}
		}

		if p.resp != nil {
			p.resp <- 1 // 发送响应
		}
	}
}

// 辅助函数，监听多个输入通道并更新状态标志
func consunit2() {
	var prog pulse // 定义一个脉冲变量

	for { // 无限循环
		select { // 使用 select 语句监听多个通道
		case <-consupdate: // 如果接收到更新通知
			// 这里没有具体的处理逻辑，只是等待更新通知
		case prog = <-conspin[0]: // 如果从第一个输入通道接收到脉冲
			if prog.val == 1 { // 如果脉冲值为1
				consinff1[0] = true // 设置第一个状态标志为 true
			}
			if prog.resp != nil { // 如果需要发送响应
				prog.resp <- 1 // 发送响应
			}
		case prog = <-conspin[1]: // 如果从第二个输入通道接收到脉冲
			if prog.val == 1 {
				consinff1[1] = true // 设置第二个状态标志为 true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		// 继续处理其余的输入通道，重复上述逻辑
		case prog = <-conspin[2]:
			if prog.val == 1 {
				consinff1[2] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[3]:
			if prog.val == 1 {
				consinff1[3] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[4]:
			if prog.val == 1 {
				consinff1[4] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[5]:
			if prog.val == 1 {
				consinff1[5] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[6]:
			if prog.val == 1 {
				consinff1[6] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[7]:
			if prog.val == 1 {
				consinff1[7] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[8]:
			if prog.val == 1 {
				consinff1[8] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[9]:
			if prog.val == 1 {
				consinff1[9] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[10]:
			if prog.val == 1 {
				consinff1[10] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[11]:
			if prog.val == 1 {
				consinff1[11] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[12]:
			if prog.val == 1 {
				consinff1[12] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[13]:
			if prog.val == 1 {
				consinff1[13] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[14]:
			if prog.val == 1 {
				consinff1[14] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[15]:
			if prog.val == 1 {
				consinff1[15] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[16]:
			if prog.val == 1 {
				consinff1[16] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[17]:
			if prog.val == 1 {
				consinff1[17] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[18]:
			if prog.val == 1 {
				consinff1[18] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[19]:
			if prog.val == 1 {
				consinff1[19] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[20]:
			if prog.val == 1 {
				consinff1[20] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[21]:
			if prog.val == 1 {
				consinff1[21] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[22]:
			if prog.val == 1 {
				consinff1[22] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[23]:
			if prog.val == 1 {
				consinff1[23] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[24]:
			if prog.val == 1 {
				consinff1[24] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[25]:
			if prog.val == 1 {
				consinff1[25] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[26]:
			if prog.val == 1 {
				consinff1[26] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[27]:
			if prog.val == 1 {
				consinff1[27] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[28]:
			if prog.val == 1 {
				consinff1[28] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		case prog = <-conspin[29]:
			if prog.val == 1 {
				consinff1[29] = true
			}
			if prog.resp != nil {
				prog.resp <- 1
			}
		}
	}
}

/**理论上consuint2函数可以优化为这段代码
func handlePulse(prog pulse, index int) {
	if prog.val == 1 {
		consinff1[index] = true
	}
	if prog.resp != nil {
		prog.resp <- 1
	}
}

func consunit2() {
	var prog pulse

	for {
		select {
		case <-consupdate:
			// 等待更新通知
		default:
			for i := 0; i < len(conspin); i++ {
				select {
				case prog = <-conspin[i]:
					handlePulse(prog, i)
				default:
					continue
				}
			}
		}
	}
}
**/